package com.codeoss.framework.view.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.codeoss.framework.context.YunContext;
import com.codeoss.framework.converter.IConverter;
import com.codeoss.framework.converter.IConverterStore;
import com.codeoss.framework.data.metadata.Column;
import com.codeoss.framework.data.metadata.TableData;
import com.codeoss.framework.data.store.ITableStore;
import com.codeoss.framework.expression.Expression;
import com.codeoss.framework.expression.IScriptServiceStore;
import com.codeoss.framework.util.LookupInfo;
import com.codeoss.framework.view.component.Component;
import com.codeoss.framework.view.component.Container;
import com.codeoss.framework.view.component.DataGrid;
import com.codeoss.framework.view.component.IDataBindSource;
import com.codeoss.framework.view.component.IDataBinding;
import com.codeoss.framework.view.component.IDataType;
import com.codeoss.framework.view.component.IFormFieldExpression;
import com.codeoss.framework.view.component.ILookup;
import com.codeoss.framework.view.component.IVarName;
import com.codeoss.framework.view.component.Image;
import com.codeoss.framework.view.component.Page;
import com.codeoss.framework.view.component.Search;
import com.codeoss.framework.view.component.Table;
import com.codeoss.framework.view.component.mobile.MListView;
import com.codeoss.framework.view.datasource.DataSourceConfig;
import com.codeoss.framework.view.model.SelectItem;
import com.codeoss.framework.view.renderer.PropSerializeMap;
import com.codeoss.framework.view.service.IVariableService;

@Service
public class PageBeanUtil {
	@Autowired
	private LookupUtil lookupUtil;
	@Autowired
	private IVariableService variableService;
	@Autowired
	private IScriptServiceStore scriptServiceStore;
	@Autowired
	private ITableStore tableStore;
	@Autowired
	private IConverterStore converterStore;
	public void getDataBindingList(Component component, List<IDataBinding> dataBindingList) {
		if (component instanceof IDataBinding && !(component instanceof Container) && !component.getType().equals("tree")) {
			dataBindingList.add((IDataBinding) component);
		}
		if (component instanceof Container) {
			Container c = (Container) component;
			for (int i = 0; i < c.getChildren().size(); i++) {
				getDataBindingList(c.getChildren().get(i), dataBindingList);
			}
		}
	}
	
	public void getFormFieldList(Component component, List<IDataBinding> dataBindingList) {
		if (component instanceof IDataBinding && !(component instanceof Container) && !component.getType().equals("tree")) {
			dataBindingList.add((IDataBinding) component);
		}
		if (component instanceof Container) {
			String type=component.getType();
			if(!"table".equals(type) && !"mlistview".equals(type)&& !"datagrid".equals(type)) {
				Container c = (Container) component;
				for (int i = 0; i < c.getChildren().size(); i++) {
					getFormFieldList(c.getChildren().get(i), dataBindingList);
				}
			}
		}
	}
	
	public void getComponent(YunContext yunContext,Page page,String type) {
		yunContext.removeAttribute("__component__");
		getComponentInner(yunContext,page,type);
	}

	protected void getComponentInner(YunContext yunContext,Component component,String type) {
		if (component.getType().equals(type)) {
			yunContext.setAttribute("__component__", component);
			return;
		}
		if (component instanceof Container) {
			Container c = (Container) component;
			for (int i = 0; i < c.getChildren().size(); i++) {
				getComponentInner(yunContext,c.getChildren().get(i),type);
			}
		}
	}
	
	public void getComponentList(YunContext yunContext,Page page,String type) {
		yunContext.removeAttribute("__componentList__");
		getComponentListInner(yunContext,page,type);
	}
	
	protected void getComponentListInner(YunContext yunContext,Component component,String type) {
		if (component.getType().equals(type)) {
			List<Component> componentList =yunContext.getAttribute("__componentList__");
			
			if (componentList == null) {
				componentList = new ArrayList<Component>();
				yunContext.setAttribute("__componentList__", componentList);
			}
			componentList.add(component);
		}
		if (component instanceof Container) {
			Container c = (Container) component;
			for (int i = 0; i < c.getChildren().size(); i++) {
				getComponentListInner(yunContext,c.getChildren().get(i),type);
			}
		}
	}
	
	public void generateFormInfo(List<IDataBinding> dataBindingList) {
		if(dataBindingList==null ||dataBindingList.size()==0) {
			return;
		}
		YunContext yunContext = YunContext.getCurrentContext();
		IDataBinding dataBinding = dataBindingList.get(0);
		DataSourceConfig dataSourceConfig = yunContext.getPage()
				.getDataSourceConfigById(((IDataBindSource) dataBinding).getDataSource());
		com.codeoss.framework.data.metadata.Table table = (com.codeoss.framework.data.metadata.Table) tableStore
				.get(dataSourceConfig.getTableName());
		for (int i = 0; i < dataBindingList.size(); i++) {
			dataBinding = dataBindingList.get(i);
			Column column = table.getColumnByColumnName(dataBinding.getDataField());
			((IDataType) dataBinding).setDataType(column.getDataType());
			if (dataBinding instanceof ILookup) {
				LookupInfo lookupInfo = ((ILookup) (dataBinding)).getLookupInfo();
				if (lookupInfo != null) {
					if (dataBinding instanceof Search) {
						Search search = (Search) dataBinding;
						Object value = variableService.getVariableValue(yunContext, search.getVarName());
						if (value == null) {
							continue;
						}
						List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo,value);
						yunContext.setAttribute(((Component) dataBinding).getId() + "_selectItem", selectItemList);
					} else {
						List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo);
						yunContext.setAttribute(((Component) dataBinding).getId() + "_selectItem", selectItemList);
					}
				}
			}
			if (dataBinding instanceof IFormFieldExpression) {
				IFormFieldExpression formFieldExpression = (IFormFieldExpression) dataBinding;
				Expression readOnlyExpression = formFieldExpression.getReadOnlyExpression();
				if (readOnlyExpression != null) {
					boolean returnValue = (boolean) scriptServiceStore.getScriptService(readOnlyExpression)
							.eval(readOnlyExpression.getScript(), yunContext.getVarValueMap());
					yunContext.setAttribute(((Component) dataBinding).getId() + "_readonly", returnValue);
				}
			}
			Component component = (Component) dataBinding;
			Expression visibleExpression = component.getVisibleExpression();
			if (visibleExpression != null) {
				boolean returnValue = (boolean) scriptServiceStore.getScriptService(visibleExpression)
						.eval(visibleExpression.getScript(), yunContext.getVarValueMap());
				yunContext.setAttribute(((Component) dataBinding).getId() + "_visible", returnValue);
			}
		}
	}

	public void generateEditableTableInfo(Table tableComponent, List<IDataBinding> dataBindingList,TableData tableData) {
		YunContext yunContext = YunContext.getCurrentContext();
		List<Map<String, PropSerializeMap>> mapList = new ArrayList<Map<String, PropSerializeMap>>();
		for (int i = 0; i < tableData.getData().size(); i++) {
			Map<String, Object> dataMap = (Map<String, Object>) tableData.getData().get(i);
			Map<String, PropSerializeMap> map = new HashMap<String, PropSerializeMap>();
			mapList.add(map);
			for (int j = 0; j < dataBindingList.size(); j++) {
				PropSerializeMap propSerializeMap = new PropSerializeMap();
				IDataBinding dataBinding = dataBindingList.get(j);
				variableService.setVariableValue(yunContext, ((IVarName) dataBinding).getVarName(),
						dataMap.get(dataBinding.getDataField()));
				map.put(((Component) dataBinding).getId(), propSerializeMap);
				propSerializeMap.put("value", dataMap.get(dataBinding.getDataField()));
				variableService.setVariableValue(yunContext, ((IVarName) dataBinding).getVarName(),
						dataMap.get(dataBinding.getDataField()));
				if (dataBinding instanceof ILookup) {
					LookupInfo lookupInfo = ((ILookup) dataBinding).getLookupInfo();
					if (lookupInfo != null) {
						List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo);
						if (selectItemList != null) {
							propSerializeMap.put("options", selectItemList);
						}
					}
				}
				if (dataBinding instanceof IFormFieldExpression) {
					IFormFieldExpression formFieldExpression = (IFormFieldExpression) dataBinding;
					Expression readOnlyExpression = formFieldExpression.getReadOnlyExpression();
					if (readOnlyExpression != null) {
						boolean returnValue = (boolean) scriptServiceStore.getScriptService(readOnlyExpression)
								.eval(readOnlyExpression.getScript(), yunContext.getVarValueMap());
						propSerializeMap.put("readonly", returnValue);
					}
				}
				Component component = (Component) dataBinding;
				Expression visibleExpression = component.getVisibleExpression();
				if (visibleExpression != null) {
					boolean returnValue = (boolean) scriptServiceStore.getScriptService(visibleExpression)
							.eval(visibleExpression.getScript(), yunContext.getVarValueMap());
					propSerializeMap.put("visible", returnValue);
				}
			}
		}
		
		IConverter datetimeConverter=converterStore.getConverter("datetime");
		IConverter dateConverter=converterStore.getConverter("date");
		IConverter timeConverter=converterStore.getConverter("time");
		IConverter booleanConverter=converterStore.getConverter("boolean");
		for(int i=0;i<mapList.size();i++) {
			Map<String, PropSerializeMap> map=mapList.get(i);
			for (int j = 0; j < dataBindingList.size(); j++) {
				IDataBinding dataBinding = dataBindingList.get(j);
				PropSerializeMap propSerializeMap=map.get(((Component) dataBinding).getId());
				Object value=propSerializeMap.get("value");
				if(value!=null) {
					String dataType=((IDataType)dataBinding).getDataType();
					if("datetime".equals(dataType)) {
						String sValue=datetimeConverter.convertObjectToString(value);
						propSerializeMap.put("value", sValue);
					}else if("date".equals(dataType)) {
						String sValue=dateConverter.convertObjectToString(value);
						propSerializeMap.put("value", sValue);
					}else if("time".equals(dataType)) {
						String sValue=timeConverter.convertObjectToString(value);
						propSerializeMap.put("value", sValue);
					}else if("boolean".equals(dataType) && !(value instanceof Boolean)) {
						propSerializeMap.put("value", booleanConverter.convertStringToObject((String)value));
					}
				}
			}
		}
		yunContext.setAttribute(tableComponent.getId() + "_data", mapList);
	}
	
	public void generateMListViewInfo(MListView mListView, List<IDataBinding> dataBindingList,TableData tableData) {
		YunContext yunContext = YunContext.getCurrentContext();
		DataSourceConfig dataSourceConfig = yunContext.getPage().getDataSourceConfigById(mListView.getDataSource());
		com.codeoss.framework.data.metadata.Table table = (com.codeoss.framework.data.metadata.Table) tableStore.get(dataSourceConfig.getTableName());
		Map<String, List<SelectItem>> selectItemMap = new HashMap<String, List<SelectItem>>();
		yunContext.setAttribute(mListView.getId() + "_tabledata", tableData);
		yunContext.setAttribute(mListView.getId() + "_selectItemMap", selectItemMap);
		for (int j = 0; j < dataBindingList.size(); j++) {
			IDataBinding dataBinding = dataBindingList.get(j);
			Component component = (Component) dataBinding;
			for (int k = 0; k < tableData.getData().size(); k++) {
				if (component instanceof Image) {
					tableData.getData().get(k).remove(dataBinding.getDataField());
				}
			}

			Column column = table.getColumnByColumnName(dataBinding.getDataField());
			((IDataType) dataBinding).setDataType(column.getDataType());
			if (dataBinding instanceof ILookup) {
				LookupInfo lookupInfo = ((ILookup) (dataBinding)).getLookupInfo();
				if (lookupInfo != null) {
					if (lookupInfo.getDataSourceConfig() != null) {
						List<Map<String, Object>> dataList = tableData.getData();
						Set<Object> keyValueSet = new HashSet<Object>();
						for (int k = 0; k < dataList.size(); k++) {
							Object value = (Object) dataList.get(k).get(dataBinding.getDataField());
							if (value != null) {
								keyValueSet.add(value);
							}
						}
						if (keyValueSet.size() == 0) {
							continue;
						}
						List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo,
								keyValueSet);
						if (selectItemList != null) {
							selectItemMap.put(component.getId(), selectItemList);
						}
					} else {
						List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo);
						if (selectItemList != null) {
							selectItemMap.put(component.getId(), selectItemList);
						}
					}
				}
			}
		}
	}
	
	public void generateDataGridInfo(DataGrid dataGrid, List<IDataBinding> dataBindingList,TableData tableData) {
		YunContext yunContext = YunContext.getCurrentContext();
		DataSourceConfig dataSourceConfig = yunContext.getPage().getDataSourceConfigById(dataGrid.getDataSource());
		com.codeoss.framework.data.metadata.Table table = tableStore.get(dataSourceConfig.getTableName());
		Map<String, List<SelectItem>> selectItemMap = new HashMap<String, List<SelectItem>>();
		yunContext.setAttribute(dataGrid.getId() + "_tabledata", tableData);
		yunContext.setAttribute(dataGrid.getId() + "_selectItemMap", selectItemMap);
		for (int j = 0; j < dataBindingList.size(); j++) {
			IDataBinding dataBinding = dataBindingList.get(j);
			Component component = (Component) dataBinding;
			for (int k = 0; k < tableData.getData().size(); k++) {
				if (component instanceof Image) {
					tableData.getData().get(k).remove(dataBinding.getDataField());
				}
			}

			Column column = table.getColumnByColumnName(dataBinding.getDataField());
			((IDataType) dataBinding).setDataType(column.getDataType());
			if (dataBinding instanceof ILookup) {
				LookupInfo lookupInfo = ((ILookup) (dataBinding)).getLookupInfo();
				if (lookupInfo != null) {
					if (lookupInfo.getDataSourceConfig() != null) {
						List<Map<String, Object>> dataList = tableData.getData();
						Set<Object> keyValueSet = new HashSet<Object>();
						for (int k = 0; k < dataList.size(); k++) {
							Object value = (Object) dataList.get(k).get(dataBinding.getDataField());
							if (value != null) {
								keyValueSet.add(value);
							}
						}
						if (keyValueSet.size() == 0) {
							continue;
						}
						List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo,
								keyValueSet);
						if (selectItemList != null) {
							selectItemMap.put(component.getId(), selectItemList);
						}
					} else {
						List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo);
						if (selectItemList != null) {
							selectItemMap.put(component.getId(), selectItemList);
						}
					}
				}
			}
		}
	}

}
